#include <QtCore>
#include <QtTest>

#include "../RScode/source/Decoder/decoder.h"

class Decoder_Test : public QObject
{
    Q_OBJECT

private:
  qlonglong m_q;
  GF        gf;
  Decoder   decoder;

public:
  Decoder_Test(): m_q(8), gf(11), decoder(7, 3) {}

private Q_SLOTS:
    void initTestCase();
    void cleanupTestCase();
    void syndrome();
    void syndrome_data();
    void chienSearch();
    void chienSearch_data();
    void errorCorrection();
    void errorCorrection_data();
    void forneyAlgorithm();
    void forneyAlgorithm_data();
    void euclideanAlgorithm();
    void euclideanAlgorithm_data();
    void decode();
    void decode_data();
};

void Decoder_Test::initTestCase()
{
}

void Decoder_Test::cleanupTestCase()
{
}

void Decoder_Test::decode()
{
  QFETCH(void *, pPoly);
  QFETCH(void *, pRes);

  QVector<qlonglong> f_ = decoder.decode(  *( (QVector<qlonglong> *)pPoly )  );
  QVector<qlonglong> res = *( (QVector<qlonglong> *)pRes );

  QVERIFY( res == f_? true: false );
}

void Decoder_Test::decode_data()
{
  QTest::addColumn<void *>("pPoly");
  QTest::addColumn<void *>("pRes");



  QTest::newRow(" decode 4 + 2*x + 6*x^2 + 5*x^3 + 1*x^4 + 7*x^5 + 3*x^6 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 4 << 2 << 6 << 5
                                                                 << 1 << 7 << 3 )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 3 << 0 << 3 )  );
  QTest::newRow(" decode 2 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 2 << 0 << 0 << 0 << 0 << 0 << 0 )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 0 << 0 << 0 )  );

//  QVector<qlonglong> f;
//  for () {
//    QTest::newRow(" decode 2 ")
//        << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << qrand()%m_q << 0 << 0 << 0 << 0 << 0 << 0 )  )
//        << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 0 << 0 << 0 )  );
//  }

}

void Decoder_Test::syndrome()
{
  QFETCH(void *, pPoly);
  QFETCH(void *, pRes);

  QVector<qlonglong> syndrome = decoder.syndrome(  *( (QVector<qlonglong> *)pPoly )  );
  QVector<qlonglong> res = *( (QVector<qlonglong> *)pRes );

  QVERIFY( res == syndrome? true: false );
}

void Decoder_Test::syndrome_data()
{
  QTest::addColumn<void *>("pPoly");
  QTest::addColumn<void *>("pRes");

  QTest::newRow(" syndrome alog(1)*x + alog(3)*x^5 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 0 << gf.alog(1) << 0 << 0 << 0 << gf.alog(3) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 1 << gf.alog(4) << gf.alog(4) << 0 )  );
  QTest::newRow(" syndrome alog(6) + alog(5)*x + alog(3)*x^2 + alog(2)*x^3 + x^4 + alog(1)*x^6 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(6) << gf.alog(5) << gf.alog(3)
                                                                 << gf.alog(2) << 1 << 0 << gf.alog(1) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(4) << gf.alog(5) << 0 << gf.alog(6) )  );
  QTest::newRow(" syndrome alog(5)*x + alog(2)*x^3 + x^4 + alog(1)*x^6 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 0 << gf.alog(5) << 0
                                                                 << gf.alog(2) << 1 << 0 << gf.alog(1) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 0 << gf.alog(6) << gf.alog(2) << gf.alog(2) )  );
  QTest::newRow(" syndrome 4 + 2*x + 6*x^2 + 5*x^3 + 1*x^4 + 7*x^5 + 3*x^6 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 4 << 2 << 6 << 5
                                                                 << 1 << 7 << 3 )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 0 << 0 << 0 << 0 )  );
}

void Decoder_Test::chienSearch()
{
  QFETCH(void *, pPoly);
  QFETCH(void *, pRes);

  QVector<qlonglong> locators = decoder.chienSearch(  *( (QVector<qlonglong> *)pPoly )  );
  QVector<qlonglong> res = *( (QVector<qlonglong> *)pRes );

  QVERIFY( res == locators? true: false );
}

void Decoder_Test::chienSearch_data()
{
  QTest::addColumn<void *>("pPoly");
  QTest::addColumn<void *>("pRes");

  QTest::newRow(" chienSearch 1 + alog(6)*x + alog(6)*x^2 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 1 << gf.alog(6) << gf.alog(6) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(5) << gf.alog(1) )  );
  QTest::newRow(" chienSearch alog(4) + alog(3)*x + alog(3)*x^2 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(4) << gf.alog(3) << gf.alog(3) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(5) << gf.alog(1) )  );
  QTest::newRow(" chienSearch 1 + x + alog(1)*x^2 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 1 << 1 << gf.alog(1) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(6) << gf.alog(2) )  );
  QTest::newRow(" chienSearch 1 + alog(6)*x ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 1 << gf.alog(6) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(6) )  );
}

void Decoder_Test::errorCorrection()
{
  QFETCH(void *, pB);
  QFETCH(void *, pLocators);
  QFETCH(void *, pErrors);
  QFETCH(void *, pRes);

  QVector<qlonglong> a = decoder.errorCorrection(  *( (QVector<qlonglong> *)pB ),
                                                   *( (QVector<qlonglong> *)pLocators ),
                                                   *( (QVector<qlonglong> *)pErrors )  );
  QVector<qlonglong> res = *( (QVector<qlonglong> *)pRes );

  QVERIFY( res == a? true: false );
}

void Decoder_Test::errorCorrection_data()
{
  QTest::addColumn<void *>("pB");
  QTest::addColumn<void *>("pLocators");
  QTest::addColumn<void *>("pErrors");
  QTest::addColumn<void *>("pRes");

  QTest::newRow(" X: alog(5) + alog(1)*x Y: alog(3) + alog(1) errorCorrection alog(1)*x + alog(3)*x^5 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 0 << gf.alog(1) << 0 << 0 << 0 << gf.alog(3) << 0 )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(5) << gf.alog(1) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(3) << gf.alog(1) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 0 << 0 << 0 << 0 << 0 << 0 << 0 )  );
  QTest::newRow(" X: alog(6) + alog(2)*x Y: alog(1) + alog(2)*x errorCorrection "
                " alog(6) + alog(5)*x + alog(3)*x^2 + alog(2)*x^3 + x^4 + alog(1)*x^6 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(6) << gf.alog(5) << gf.alog(3)
                                                                 << gf.alog(2) << 1 << 0 << gf.alog(1) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(6) << gf.alog(2) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(1) << gf.alog(2) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(6) << gf.alog(5) << gf.alog(5)
                                                                 << gf.alog(2) << 1 << 0 << 0 )  );
}

void Decoder_Test::forneyAlgorithm()
{
  QFETCH(void *, pValErrorsPoly);
  QFETCH(void *, pDerivLocatorPoly);
  QFETCH(void *, pLocators);
  QFETCH(void *, pRes);

  QVector<qlonglong> errors = decoder.forneyAlgorithm(  *( (QVector<qlonglong> *)pValErrorsPoly ),
                                                        *( (QVector<qlonglong> *)pDerivLocatorPoly ),
                                                        *( (QVector<qlonglong> *)pLocators )  );
  QVector<qlonglong> res = *( (QVector<qlonglong> *)pRes );

  QVERIFY( res == errors? true: false );
}

void Decoder_Test::forneyAlgorithm_data()
{
  QTest::addColumn<void *>("pValErrorsPoly");
  QTest::addColumn<void *>("pDerivLocatorPoly");
  QTest::addColumn<void *>("pLocators");
  QTest::addColumn<void *>("pRes");

  QTest::newRow("\n forneyAlgorithm "
                "\n valErrorsPoly: alog(4) + x "
                "\n derivLocatorPoly: alog(3) "
                "\n locators: alog(5) + alog(1)*x \n")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(4) << 1 )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(3) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(5) << gf.alog(1) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(3) << gf.alog(1) )  );
  QTest::newRow("\n forneyAlgorithm "
                "\n valErrorsPoly: 1 + alog(3)*x "
                "\n derivLocatorPoly: alog(6) "
                "\n locators: alog(5) + alog(1)*x \n")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 1 << gf.alog(3) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(6) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(5) << gf.alog(1) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(3) << gf.alog(1) )  );
  QTest::newRow("\n forneyAlgorithm "
                "\n valErrorsPoly: alog(4) + x "
                "\n derivLocatorPoly: 1 "
                "\n locators: alog(6) + alog(2)*x \n")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(4) << 1 )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 1 )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(6) << gf.alog(2) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(1) << gf.alog(2) )  );
}


void Decoder_Test::euclideanAlgorithm()
{
  QFETCH(void *, pSyndrome);
  QFETCH(void *, pResLocatorPoly);
  QFETCH(void *, pResValErrorsPoly);

  QVector<qlonglong> valErrorsPoly;
  QVector<qlonglong> locatorPoly = decoder.euclideanAlgorithm(  *( (QVector<qlonglong> *)pSyndrome ),
                                                                 valErrorsPoly  );
  QVector<qlonglong> resLocatorPoly = *( (QVector<qlonglong> *)pResLocatorPoly );
  QVector<qlonglong> resValErrorsPoly = *( (QVector<qlonglong> *)pResValErrorsPoly );

  QVERIFY( resLocatorPoly == locatorPoly? true: false );
  QVERIFY( resValErrorsPoly == valErrorsPoly? true: false );
}

void Decoder_Test::euclideanAlgorithm_data()
{
  QTest::addColumn<void *>("pSyndrome");
  QTest::addColumn<void *>("pResLocatorPoly");
  QTest::addColumn<void *>("pResValErrorsPoly");

  QTest::newRow(" euclideanAlgorithm 1 + alog(4)*x + alog(4)*x^2 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 1 << gf.alog(4) << gf.alog(4) << 0 )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(4) << gf.alog(3) << gf.alog(3) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(4) << 1 )  );
  QTest::newRow(" euclideanAlgorithm alog(4) + alog(5)*x + alog(6)*x^3 ")
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(4) << gf.alog(5) << 0 << gf.alog(6) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << 1 << 1 << gf.alog(1) )  )
      << (void *)(  new QVector<qlonglong>( QVector<qlonglong>() << gf.alog(4) << 1 )  );
}

QTEST_APPLESS_MAIN(Decoder_Test);

#include "decoder_test.moc"
